#define DEBUG_VS   // Uncomment this line to debug vertex shaders
#define DEBUG_PS   // Uncomment this line to debug pixel shaders


using System;
using System.Drawing;
using System.Xml;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using D3D = Microsoft.DirectX.Direct3D;

namespace GPU_NN
{
	    /// <summary>
    /// Structure Description: The structure here is defined so that when
    ///         passing a vertex we know exactly what the form of the vertex
    ///         actually looks like
    /// 
    /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
    /// 
    /// Edited By:										Date:
    /// Reason For Editing:
    /// </summary>
    public struct myownvertexformat
	{
		public Vector3 Pos;
		public int Color;

		public myownvertexformat(Vector3 _Pos, int _Color)
		{
			Pos = _Pos;
			Color = _Color;
		}
	}

	/// <summary>
    /// Function Description: This method sets all the default information 
    ///         for our form and how to display it.  it also sets up our
    ///         device and vertexbuffer so that there are no unset variables
    /// 
    /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
    /// 
    /// Edited By:										Date:
    /// Reason For Editing:
    /// </summary>
    public class WinForm : System.Windows.Forms.Form
    {
        /// <summary>
        /// x position of the users eye
        /// </summary>
        public int eyex = 200;
        /// <summary>
        /// y position of the users eye
        /// </summary>
        public int eyey = 200;
        /// <summary>
        /// z position of the users eye
        /// </summary>
        public int eyez = -600;
        /// <summary>
        /// Object being displayed x position
        /// </summary>
        public int objectx = 200;
        /// <summary>
        /// Object being displayed y position
        /// </summary>
        public int objecty = 200;
        /// <summary>
        /// Object being displayed z position
        /// </summary>
        public int objectz = 0;

        /// <summary>
        /// Width of the image we are to display
        /// </summary>
        public static double imagewidth = 400.00;
        /// <summary>
        /// Height of the image we are to display
        /// </summary>
        public static double imageheight = 400.00;

        /// <summary>
        /// x value of the center of the image used for distance calculations
        /// </summary>
        public double xcenter = 0;//imagewidth / 2;
        /// <summary>
        /// y value of the center of the image used for distance calculations
        /// </summary>
        public double ycenter = 0;//imageheight / 2;

        /// <summary>
        /// Array of x vertex of the image breakdown
        /// </summary>
        public double[] x = new double[(int)imagewidth + 1];
        /// <summary>
        /// y value of the image breakdown
        /// </summary>
        public double y = 0;
        /// <summary>
        /// Array to hold the distance to center for each vertex being used
        /// </summary>
        public double[] d = new double[(int)imagewidth + 1];
        /// <summary>
        /// Random variable used to set bias
        /// </summary>
        public Random randnum = new Random();
        /// <summary>
        /// a random variable used in the NN
        /// </summary>
        public double bias = 0.0;
        /// <summary>
        /// Double scripted array used for the output of the whole images vertex
        /// </summary>
        public double[,] TotalOutput = new double[(int)imagewidth + 1, (int)imageheight + 1];
        /// <summary>
        /// used as the x subscript in the array
        /// </summary>
        public int xcount = 0;
        /// <summary>
        /// used as the y subscript in the array
        /// </summary>
        public int ycount = 0;
        /// <summary>
        /// This is the boolean to check if the NN has run its course
        /// </summary>
        public bool totaldone = false;
        /// <summary>
        /// Array to hold the number of vertices that are in the image
        /// this is in my own vertex format
        /// </summary>
        public myownvertexformat[] vertices = new myownvertexformat[160000];
        /// <summary>
        /// used to hold the values that need to be streamed into the .fx file
        /// for fast vertex processing
        /// </summary>
        public VertexDeclaration vd;
        
        /// <summary>
        /// In our DirectX app, we will first load the .fx file into an
        /// Effect object, and set the transformation matrix. So first we
        /// need an Effect object to store our effect
        /// </summary>
        public Effect effect;

        private System.ComponentModel.Container components = null;
        /// <summary>
        /// this is our one and only graphics device
        /// </summary>
        private D3D.Device device;
        /// <summary>
        /// This is used to hold information on the buffer to be output
        /// to the screen 
        /// </summary>
        private VertexBuffer vb;
        /// <summary>
        /// used to hold the eye position matrix
        /// </summary>
        private Vector3 CameraPos;
        /// <summary>
        /// used to hold the view matrix for displaying the image
        /// </summary>
        private Matrix matView;
        /// <summary>
        /// used to hold the matrix for the projection.  our viewable area or pyramid
        /// </summary>
        private Matrix matProjection;
        /// <summary>
        /// used for updating and checking our frame rate
        /// </summary>
        private int LastTickCount = 1;
        /// <summary>
        /// used to hold the count of frames 
        /// </summary>
        private int Frames = 0;
        /// <summary>
        /// hold the previous frame rate from the last check
        /// </summary>
        private double LastFrameRate = 0;
        /// <summary>
        /// holds the type of text that will be displayed on the form
        /// </summary>
        private D3D.Font text;
        /// <summary>
        /// the count of the nodes when read in from the XML
        /// </summary>
        public int nTotalNodes;
        /// <summary>
        /// used when cycling through the nodes array
        /// </summary>
        public int nodecount;
        /// <summary>
        /// used for debugging and seeing the output from the XML parser
        /// </summary>
        public String contents;
        /// <summary>
        /// this hold the array of nodes read in from the XML file
        /// </summary>
        public Node[] p_NetworkNodes;

        /// <summary>
        /// button used to run the NN and get an output
        /// </summary>
        private Button btnRunNN;
        /// <summary>
        /// button used to read in an XML file
        /// </summary>
        private Button btnReadXML;
        /// <summary>
        /// used for displaying position on screen
        /// </summary>
        private Label label1;

		/// <summary>
        /// Function Description: This is the main form of the application it
        ///         holds all fo the information for setup this is also where
        ///         we set the bias for the Neural Network
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public WinForm()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            //this.TransparencyKey = Color.Yellow;

            bias = .75;// randnum.NextDouble() * 2;
        }

		/// <summary>
        /// Function Description: This method initializes the device (our graphics card) and
        ///         sets our callback function for changing the size of the form 
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void InitializeDevice()
		{
			PresentParameters presentParams = new PresentParameters();
			presentParams.Windowed = true;
			presentParams.SwapEffect = SwapEffect.Discard;
			presentParams.AutoDepthStencilFormat = DepthFormat.D16;
			presentParams.EnableAutoDepthStencil = true;

			Caps DevCaps = D3D.Manager.GetDeviceCaps(0, D3D.DeviceType.Hardware);
			D3D.DeviceType DevType = D3D.DeviceType.Reference;
			CreateFlags DevFlags = CreateFlags.SoftwareVertexProcessing;
			if ((DevCaps.VertexShaderVersion >= new Version(2, 0)) && (DevCaps.PixelShaderVersion >= new Version(2, 0)))
			{
				DevType = D3D.DeviceType.Hardware;
				if (DevCaps.DeviceCaps.SupportsHardwareTransformAndLight)
				{
					DevFlags = CreateFlags.HardwareVertexProcessing;
					if (DevCaps.DeviceCaps.SupportsPureDevice)
					{
						DevFlags |= CreateFlags.PureDevice;
					}
				}
			}
			device = new D3D.Device(0, DevType, this, DevFlags, presentParams);
			device.DeviceReset += new EventHandler(this.HandleDeviceReset);
		}

		 /// <summary>
        /// Function Description: This is code off the internet on how to handle a key 
        ///         press arrow or control if there are buttons or other controls on 
        ///         the page.  it passes control from the controls on the page to the 
        ///         main form so that it can register your key press
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
		{
			if (keyData == Keys.X || keyData == Keys.Z || keyData == Keys.R || keyData == Keys.L || keyData == Keys.U || keyData == Keys.D || keyData == Keys.I || keyData == Keys.O || keyData == Keys.Up || keyData == Keys.Down || keyData == Keys.Left || keyData == Keys.Right)
			{
				Form1_KeyDown(this, new KeyEventArgs(keyData));
				return true;
			}
			return base.ProcessCmdKey(ref msg, keyData);
		}
		
		 /// <summary>
        /// Function Description: This is the actual handling of the arrows key press 
        ///         to either zoom in or to zoom out and move left and right to see things
        ///         it lets the user move the screen objects or the eyepoint itself
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_KeyDown(object sender, KeyEventArgs e)
		{
			//Console.WriteLine(e.KeyCode.ToString());
			if (e.KeyCode == Keys.Z)
			{
				objectz = objectz + 2;
			}
			if (e.KeyCode == Keys.X)
			{
				objectz = objectz - 2;
			}
			if (e.KeyCode == Keys.R)
			{
				objectx = objectx + 2;
			}
			if (e.KeyCode == Keys.L)
			{
				objectx = objectx - 2;
			}
			if (e.KeyCode == Keys.U)
			{
				objecty = objecty + 2;
			}
			if (e.KeyCode == Keys.D)
			{
				objecty = objecty - 2;
			}
			if (e.KeyCode == Keys.Up)
			{
				// this is the zoom in
				eyey = eyey + 2;
			}
			if (e.KeyCode == Keys.Down)
			{
				eyey = eyey - 2;
			}
			if (e.KeyCode == Keys.I)
			{
				eyez = eyez + 2;
			}
			if (e.KeyCode == Keys.O)
			{
				eyez = eyez - 2;
			}
			if (e.KeyCode == Keys.Left)
			{
				eyex = eyex - 2;
			}
			if (e.KeyCode == Keys.Right)
			{
				eyex = eyex + 2;
			}
		}

		/// <summary>
        /// Function Description: this is the callback for the changing of the 
        ///         window size it restarts the drawing process
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HandleDeviceReset(object sender, EventArgs e)
		{
			FillResources();
		}

		/// <summary>
        /// Function Description: Allocation of resources for use of the GPU
        ///         vertexBuffer is the holder for all the vertices when
        ///         using the cpu only
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void AllocateResources()
		{
			vb = new VertexBuffer(typeof(myownvertexformat), 160000, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture0, Pool.Managed);
			InitializeFont();

			effect = D3D.Effect.FromFile(device, @"../../GPU.fx", null, null, ShaderFlags.None, null);
		}

		/// <summary>
        /// Function Description: Allocation of resources for use of the GPU
        ///         vertexBuffer is the holder for all the vertices when
        ///         using the cpu only
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void FillResources()
		{
			// these vertices need to be filled with the x, and y data that is read in
			if (!totaldone)
			{
				vertices[0] = new myownvertexformat(new Vector3(2f, -2f, -2f), Color.Red.ToArgb());
				vertices[1] = new myownvertexformat(new Vector3(0f, 2f, 0f), Color.Yellow.ToArgb());
				vertices[2] = new myownvertexformat(new Vector3(-2f, -2f, 2f), Color.Green.ToArgb());

				vb.SetData(vertices, 0, LockFlags.None);

				SetUpCamera();
				device.RenderState.Lighting = false;
			}
			else
			{
				for(int yvalue = 0;yvalue < 400;yvalue++)
				{
					for (int xvalue = 0; xvalue< 400; xvalue++)
					{
						if(-1.0 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.75)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.White.ToArgb());
						else if (-.75 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.50)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.LightSkyBlue.ToArgb());
						else if (-.50 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.25)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.LightBlue.ToArgb());
						else if (-.25 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < 0.0)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.SkyBlue.ToArgb());
						else if (0.0 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .25)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.Blue.ToArgb());
						else if (.25 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .50)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.DarkBlue.ToArgb());
						else if (.50 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .75)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.DeepSkyBlue.ToArgb());
						else if (.75 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] <= 1)
							vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.Black.ToArgb());                        
					}
				}
				vb.SetData(vertices, 0, LockFlags.None);

				SetUpCamera();
				device.RenderState.Lighting = false;
			}
			VertexElement[] velements = new VertexElement[]{
				new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
				new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
				VertexElement.VertexDeclarationEnd
			};
			vd = new VertexDeclaration(device, velements);
		}

		/// <summary>
        /// Function Description: This method just initializes the font that we use
        ///         to display our text to the form for debugging
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void InitializeFont()
		{
			System.Drawing.Font systemfont = new System.Drawing.Font("Arial", 12f, FontStyle.Regular);
			text = new D3D.Font(device, systemfont);
		}

		/// <summary>
        /// Function Description: This method overrides the OnPaint of the form 
        ///         that displays to our user.  it also writes whatever we want
        ///         to the screen for testing and refreshes all the controls 
        ///         for every drawing of the framebuffer that comes through
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="e"></param>
        private void DrawMesh(Mesh mesh, Material[] meshmaterials, Texture[] meshtextures)
		{
			for (int i = 0; i < meshmaterials.Length; i++)
			{
				if (meshtextures.Length > 3) device.SetTexture(0, meshtextures[i]);
				mesh.DrawSubset(i);
			}
		}

		protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
		{
			label1.Text = "eyex= " + eyex + "  " + "eyey= " + eyey + "  " + "eyez= " + eyez +
				"\n" + "objectx= " + objectx + " " + "objecty= " + objecty + " " + "objectz= " + objectz + "\n";
			SetUpCamera();
			device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
			device.BeginScene();

			device.Transform.World = Matrix.Identity;
			device.VertexFormat = CustomVertex.PositionColored.Format;
            
			// indicates which vertex stream we want to be drawn from
			device.SetStreamSource(0, vb, 0);
			//device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

			// This sets up our device to use our vertex declaration data
			device.VertexDeclaration = vd;
            
			// this sets the tech
			effect.Technique = "Simplest";
			// This line sets the xViewProjection variable in the .fx file to dispay 3D to 2D
			effect.SetValue("xViewProjection", matView * matProjection);

			// Drawing the old lines way through only the cpu
			device.DrawPrimitives(PrimitiveType.LineList, 0, 80000);
            
			// Now we need to run our points throught the .fx file
			int numpasses = effect.Begin(0);
			for (int i = 0; i < numpasses; i++)
			{
				// Starting the flow of the data through the .fx file
				effect.BeginPass(i);
				// This line needs to be altered to allow me to draw the entire picture
				device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
				// End of this particular pass
				effect.EndPass();
			}
			effect.End();
            
			btnReadXML.BringToFront();
			btnRunNN.BringToFront();
			UpdateFramerate();

			device.EndScene();
			btnReadXML.Refresh();
			btnRunNN.Refresh();
			label1.Refresh();

			device.Present();
			this.Invalidate();
		}

		/// <summary>
        /// Function Description: This method updates the frame rate that you see
        ///         in the bottom left corner of the form that comes up this is just
        ///         what comes with the tutorial that the implementation was learned
        ///         from.  it may be removed if you wish
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void UpdateFramerate()
		{
			Frames++;
			if (Math.Abs(Environment.TickCount - LastTickCount) > 1000)
			{
				LastFrameRate = (double)Frames * 1000 / Math.Abs(Environment.TickCount - LastTickCount);
				LastTickCount = Environment.TickCount;
				Frames = 0;
			}
			text.DrawText(null, string.Format("Framerate : {0:0.00} fps", LastFrameRate), new Point(10, 430), Color.Red);
		}

		/// <summary>
        /// Function Description: This method is used to set the view of the camera and the 
        ///         layout of the picture that is going to be rendered
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void SetUpCamera()
		{
			//CameraPos = new Vector3(200, 200, -600);
			CameraPos = new Vector3(eyex, eyey, eyez);
			matProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
			//matView = Matrix.LookAtLH(CameraPos, new Vector3(200, 200, 0), new Vector3(0, 1, 0));
			matView = Matrix.LookAtLH(CameraPos, new Vector3(objectx, objecty, objectz), new Vector3(0, 1, 0));

			device.Transform.Projection = matProjection;
			device.Transform.View = matView;

			//CameraPos = new Vector3(0, 5, 5);
			//matProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, .5f, 20f);
			//matView = Matrix.LookAtLH(CameraPos, new Vector3(0, 0, 0), new Vector3(0, 1, 0));

			//device.Transform.Projection = matProjection;
			//device.Transform.View = matView;

		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		private void InitializeComponent()
		{
			this.btnRunNN = new System.Windows.Forms.Button();
			this.btnReadXML = new System.Windows.Forms.Button();
			this.label1 = new System.Windows.Forms.Label();
			this.SuspendLayout();
			// 
			// btnRunNN
			// 
			this.btnRunNN.Location = new System.Drawing.Point(396, 11);
			this.btnRunNN.Name = "btnRunNN";
			this.btnRunNN.Size = new System.Drawing.Size(84, 23);
			this.btnRunNN.TabIndex = 1;
			this.btnRunNN.Text = "Run Network";
			this.btnRunNN.Click += new System.EventHandler(this.btnRunNN_Click);
			// 
			// btnReadXML
			// 
			this.btnReadXML.Location = new System.Drawing.Point(12, 12);
			this.btnReadXML.Name = "btnReadXML";
			this.btnReadXML.Size = new System.Drawing.Size(83, 23);
			this.btnReadXML.TabIndex = 0;
			this.btnReadXML.Text = "Read XML";
			this.btnReadXML.Click += new System.EventHandler(this.btnReadXML_Click);
			// 
			// label1
			// 
			this.label1.BackColor = System.Drawing.Color.Black;
			this.label1.ForeColor = System.Drawing.Color.Red;
			this.label1.Location = new System.Drawing.Point(268, 431);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(225, 35);
			this.label1.TabIndex = 2;
			// 
			// WinForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(492, 466);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.btnRunNN);
			this.Controls.Add(this.btnReadXML);
			this.Name = "WinForm";
			this.Text = "Group 3 GPU-NN Picture";
			this.ResumeLayout(false);

		}

		/// <summary>
        /// Function Description: This is the Main loop of the application it 
        ///         initializes then allocates then the user reads the XML creates 
        ///         the NN and then runs the NN
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        static void Main()
		{
			using (WinForm our_directx_form = new WinForm())
			{
				our_directx_form.InitializeDevice();
				our_directx_form.AllocateResources();
				//our_directx_form.ReadXML();
				//our_directx_form.RunNN();
				our_directx_form.FillResources();
				Application.Run(our_directx_form);
			}
		}

		/// <summary>
        /// Function Description: This is a function used to find the node with a certain id
        ///         then this node is returned and used elsewhere in the program
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        Node FindNode(int id)
		{
			Node node = null;
			// Need to initialize the links
			for (int i = 0; i < nTotalNodes; i++)
			{
				if (p_NetworkNodes[i].GetNodeID() == id)
				{
					node = p_NetworkNodes[i];
				}
			}
			return node;
		}

		/// <summary>
        /// Function Description: This is the code that will set up the inputs to each of the nodes
        ///         in the NN this is just to setup a count on the number of inputs 
        ///         the node should have before being fired(executed)
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        void SetInputs()
		{
			Link link;
			ArrayList list;
			for (int i = 0; i < nTotalNodes; i++)
			{
				// This will return the linkArray
				list = p_NetworkNodes[i].GetNodeLinkList();
				// Cycle through the linkArray finding the targets of this node
				// set the targets to have another input for this node
				for (int j = 0; j < list.Count; j++)
				{
					link = (Link)list[j];
					// Find the Target node so that we can set it
					for (int k = 0; k < nTotalNodes; k++)
					{
						if (p_NetworkNodes[k].GetNodeID() == link.GetLinkTargetID())
						{
							// Set the inputArray to have another input
							p_NetworkNodes[k].m_nNumofInputs = p_NetworkNodes[k].m_nNumofInputs + 1;
						}
					}
				}
			}
		}

		/// <summary>
        /// Function Description: Button press to read in an XML file.  It parses looking for
        ///			only the elements that are necessary to fill in our Neural Network or the
        ///			nodes and links in our network.
        ///
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void btnReadXML_Click(object sender, EventArgs e)
		{
			// Set the status of the buttons
			btnRunNN.Enabled = true;
			btnReadXML.Enabled = false;

			// String for debugging
			//String contents;

			// Xml reader to parse the xml file
			XmlTextReader Reader = new XmlTextReader("network.xml");
			//Reader.;//
			//Reader.openCreate("network.xml");

			// Read in the xml file
			while (Reader.Read())
			{
				if (Reader.NodeType == XmlNodeType.Element)
				{
					if (Reader.Name == "links")
					{
						// Only Attribute is number of links
						contents += Reader.GetAttribute(0);

						// Create an array of the links
						//p_NodeLinks = new cli.array<CNode^>(Convert.ToInt32(contents));
					}
					else if (Reader.Name == "nodes")
					{
						// Only Attribute is number of nodes
						//contents = Reader.Name;
						contents += Reader.GetAttribute(0);
						nTotalNodes = Convert.ToInt32(Reader.GetAttribute(0));

						// Create an array of the nodes
						p_NetworkNodes = new Node[nTotalNodes];
					}
					else if (Reader.Name == "link")
					{
						// Need to look up this node in the array of nodes
						Node tempNode = new Node();
						Link link = new Link();
                        
						// This is an element move to the attribute
						Reader.MoveToNextAttribute();

						// an EndElement will stop this loop through the "node"
						while (Reader.NodeType != XmlNodeType.EndElement)
						{
							// whitespace is what it is called when it reads this /> 
							// in an xml file
							if (Reader.NodeType == XmlNodeType.Whitespace)
							{
								// go to next line and get attribute count for that subnode
								Reader.Read();
							}

							if (Reader.NodeType == XmlNodeType.Text)
							{
								// This is only needed for the Activation node
								// his xml file is poorly formatted
								contents += "Weight=";
								contents += Reader.Value + "\n";
								String don;
								don = Reader.Value;
								double weight;
								System.Decimal di;
								di = Convert.ToDecimal(don);
								weight = (double)di;
								link.SetLinkWeight(weight);
								//tempNode.SetNodeLinkWeight(weight, nTotalNodes);
							}

							if (Reader.NodeType == XmlNodeType.Element)
							{
								if (Reader.Name == "link")
								{
									// Start of new Element go to attribute
									Reader.Read();
								}
								if (Reader.Name == "marking")
								{
									// Start of new Element go to attribute
									//Reader.MoveToNextAttribute();
									// This is the marking Branch
									//contents += Reader.GetAttribute(Reader.Name) + " ";

									// Go to next attribute
									//Reader.MoveToNextAttribute();
									// This is the marking Branch ID
									//contents += Reader.GetAttribute(Reader.Name) + " ";

									// Go to Next Line
									Reader.Read();
								}
								if (Reader.Name == "source")
								{
									// Start of new Element go to attribute
									Reader.MoveToNextAttribute();
									// This is the source Branch
									contents += Reader.GetAttribute(Reader.Name) + " ";

									// Go to next attribute
									Reader.MoveToNextAttribute();
									// This is the source Branch ID
									contents += Reader.GetAttribute(Reader.Name) + " ";

									tempNode = FindNode(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
									tempNode.SetNodeLink(link);
									// Go to Next Line
									Reader.Read();
								}
								if (Reader.Name == "target")
								{
									// Start of new Element go to attribute
									Reader.MoveToNextAttribute();
									// This is the target Branch
									contents += Reader.GetAttribute(Reader.Name) + " ";

									// Go to next attribute
									Reader.MoveToNextAttribute();
									// This is the target Branch ID
									contents += Reader.GetAttribute(Reader.Name) + " ";

									link.SetLinkTargetID(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
									//tempNode.SetNodeLink(Convert.ToInt32(Reader.GetAttribute(Reader.Name)), nTotalNodes);
									// Go to Next Line
									Reader.Read();
								}
							}
							// Go to next subnode in node
							Reader.Read();
						}
					}
						// This is now done sort of
					else if (Reader.Name == "node")
					{
						// Create a new Node
						p_NetworkNodes[nodecount] = new Node(nTotalNodes);//[nTotalNodes];

						// Move to the first attribute
						//contents = Reader.Name;
						Reader.MoveToNextAttribute();

						// an EndElement will stop this loop through the "node"
						while (Reader.NodeType != XmlNodeType.EndElement)
						{
							// whitespace is what it is called when it reads this "/>" 
							// in an xml file
							if (Reader.NodeType == XmlNodeType.Whitespace)
							{
								// go to next line and get attribute count for that subnode
								Reader.Read();
							}

							// This is only needed for the Activation node
							// his xml file is poorly formatted
							if (Reader.NodeType == XmlNodeType.Text)
							{
								contents += "Activation=" + Reader.Value + "\n";
								p_NetworkNodes[nodecount].SetNodeFunction(Reader.Value);
							}

							if (Reader.NodeType == XmlNodeType.Element)
							{
								// Start of new Element go to attribute
								Reader.MoveToNextAttribute();
							}

							// If type is an attribute see what attribute it is
							// and save it as needed
							if (Reader.NodeType == XmlNodeType.Attribute)
							{
								// Just a label go to next attribute
								if (Reader.Name == "label")
								{
									p_NetworkNodes[nodecount].SetNodeInput(Reader.GetAttribute(Reader.Name));
									Reader.MoveToNextAttribute();
								}

								// Type need this for Network save it
								if (Reader.Name == "type")
								{
									contents += Reader.GetAttribute(Reader.Name) + " ";
									p_NetworkNodes[nodecount].SetNodeType(Reader.GetAttribute(Reader.Name));

									if (Reader.GetAttribute(Reader.Name) == "in")
									{
										p_NetworkNodes[nodecount].m_nNumofInputs = p_NetworkNodes[nodecount].m_nNumofInputs + 1;
									}
								}

								// Just the Marking element go to the attribute
								if (Reader.Name == "marking")
								{
									Reader.MoveToNextAttribute();
								}

								// Branch attribute may be needed save to Node
								// and move to next attribute
								if (Reader.Name == "branch")
								{
									contents += Reader.GetAttribute(Reader.Name) + " ";
									p_NetworkNodes[nodecount].SetNodeBranch(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
									Reader.MoveToNextAttribute();
								}

								// ID attribute needed for traversing the NN save to Node
								// and move to next attribute
								if (Reader.Name == "id")
								{
									contents += Reader.GetAttribute(Reader.Name) + " ";
									p_NetworkNodes[nodecount].SetNodeID(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
									Reader.MoveToNextAttribute();
								}
							}
							// Done with this node read the next line
							Reader.Read();
						}
						// increment the node count 
						nodecount = nodecount + 1;
					}
				}
			}
			//MessageBox.Show(contents, "xml file", MessageBoxButtons.OK);
			Console.WriteLine(contents);
			// Need to set the inputs for all of the nodes need to cycle through
			// the nodes and set the inputs from the target info
			SetInputs();
		}

		/// <summary>
        /// Function Description: The running of the NN only available after the NN XML file has
        ///         been read in this will do all the tracing needed through the NN that was created
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRunNN_Click(object sender, EventArgs e)
		{
			bool done = false;
			bool xdone = false;
			bool ydone = false;
			bool ddone = false;
			bool biasdone = false;
			double xposition = -1.0;
			double yposition = 1.0;

			Random newbias = new Random();
			bias = newbias.NextDouble();
			// fill the data to be worked on
			for (int loop = 0; loop < imagewidth;loop++)
			{
				//x[loop] = (double)(1.0 / imagewidth) * loop;
				x[loop] = xposition + ((2 / imagewidth) * loop); 
			}
			for (int loop = 0; loop < imagewidth + 1; loop++)
			{
				y = yposition - ((2 / imageheight) * loop);
				for (int j = 0; j < imageheight + 1; j++)
				{
					done = false;
					//y = (2.0 / imageheight) * j;
					// fill the data to be worked on
					for (int i = 0; i < imagewidth + 1; i++)
					{
						// Distance to center from point being manipulated by NN
						d[i] = (double)Math.Sqrt(((x[i] - xcenter) * (x[i] - xcenter)) + ((y - ycenter) * (y - ycenter)));
					}

					// Find the inputs first
					for (int k = 0; k < nodecount; k++)
					{
						if (p_NetworkNodes[k].GetInputName() == "x")
						{
							p_NetworkNodes[k].UpdateInputValue(x[j]);
							xdone = true;
						}
						if (p_NetworkNodes[k].GetInputName() == "y")
						{
							p_NetworkNodes[k].UpdateInputValue(y);
							ydone = true;
						}
						if (p_NetworkNodes[k].GetInputName() == "d")
						{
							p_NetworkNodes[k].UpdateInputValue(d[j]);
							ddone = true;
						}
						if (p_NetworkNodes[k].GetInputName() == "bias")
						{
							p_NetworkNodes[k].UpdateInputValue(bias);
							biasdone = true;
						}
						if (xdone && ydone && ddone && biasdone)
						{
							xdone = false;
							ydone = false;
							ddone = false;
							biasdone = false;
							break;
						}
					}
					//////////////////////////////////////////////////
					// Running of the NN 
					// Loop through the nodes checking if the input is 
					// all there and ready to go
					//////////////////////////////////////////////////
					while (!done)
					{
						for (int i = 0; i < nodecount; i++)
						{
							if (p_NetworkNodes[i].m_nNumofInputs == p_NetworkNodes[i].inputArray.Count && !p_NetworkNodes[i].finished)
							{
								// now we can run this node
								double outputvalue = p_NetworkNodes[i].GetNodeOutput();
								// now we need to fill in the links with output * weight
								FillLinksForThisNode(outputvalue, p_NetworkNodes[i]);
								// set this node to finished so i don't process it again
								p_NetworkNodes[i].finished = true;
								// if this is the last node then we are done
								if (p_NetworkNodes[i].GetNodeType() == "out")
								{
									TotalOutput[xcount, ycount] = outputvalue;
									//Console.WriteLine("Total Output ({0},{1}) = {2}", xcount, ycount, TotalOutput[xcount, ycount]);
									xcount = j;
									ycount = loop;
									done = true;
								}
							}
						}
					}
					ClearInput();
				}
			}
			totaldone = true;
			FillResources();
		}

		/// <summary>
        /// Function Description: This clears all the inputs for cycling through the NN again and again
        ///         as the inputs of the image are put in
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void ClearInput()
		{
			//bool xdone = false;
			//bool ydone = false;
			//bool ddone = false;
			//bool biasdone = false;

			// Find the inputs first
			for (int k = 0; k < nodecount; k++)
			{
				for (int j = 0; j < p_NetworkNodes[k].inputArray.Count; j++)
				{
					p_NetworkNodes[k].inputArray.Clear();
				}
				p_NetworkNodes[k].finished = false;
			}
		}

		/// <summary>
        /// Function Description: This function will fill the links for an input node it shows 
        ///         all of the nodes that the input node is outputting to
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="output"></param>
        /// <param name="node"></param>
        public void FillLinksForThisNode(double output, Node node)
		{
			ArrayList linklist;
			linklist = node.GetNodeLinkList();
			if (node.GetNodeType() == "out")
			{
				return;
			}
			for (int j = 0; j < linklist.Count; j++)
			{
				Link link = (Link)linklist[j];
				// Find the Target node so that we can set it
				for (int k = 0; k < nTotalNodes; k++)
				{
					if (p_NetworkNodes[k].GetNodeID() == link.GetLinkTargetID())
					{
						// Set the inputArray to have another input
						p_NetworkNodes[k].inputArray.Add(output * link.GetLinkWeight());
					}
				}
			}
		}
	}
}
